/*******************************************************************************
 *
 * Copyright (c) 2008-2011 ayound@gmail.com, guwei8576431@gmail.com
 * This program and the accompanying materials
 * are made available under the terms of the GNU GENERAL PUBLIC LICENSE 
 * which accompanies this distribution, and is available at
 * http://dev.perl.org/licenses/gpl1.html
 * All rights reserved.
 * 
 * Created on 2009-11-1
 *******************************************************************************/

package org.cgtw.scriptprofile.widget;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

import javax.swing.table.AbstractTableModel;

import org.cgtw.scriptprofile.server.model.ProfileData;
import org.cgtw.scriptprofile.server.model.ProfileItem;
import org.cgtw.scriptprofile.ui.message.ScriptProfileMessages;

@SuppressWarnings("serial")
public class ProfileTableViewerModel extends AbstractTableModel {
	protected int sortCol = 0;

	protected boolean isSortAsc = true;

	Vector<ProfileItemBean> vector = new Vector<ProfileItemBean>();

	String[] columnNames = new String[] {
			ScriptProfileMessages.getString("ScriptProfileMainFrame.Function"),
			ScriptProfileMessages.getString("ScriptProfileMainFrame.Calls"),
			ScriptProfileMessages.getString("ScriptProfileMainFrame.Percent"),
			ScriptProfileMessages.getString("ScriptProfileMainFrame.OwnerTime"),
			ScriptProfileMessages.getString("ScriptProfileMainFrame.Time"),
			ScriptProfileMessages.getString("ScriptProfileMainFrame.Avg"),
			ScriptProfileMessages.getString("ScriptProfileMainFrame.Min"),
			ScriptProfileMessages.getString("ScriptProfileMainFrame.Max"),
			ScriptProfileMessages.getString("ScriptProfileMainFrame.File"), };

	public ProfileTableViewerModel() {
		vector.removeAllElements();
		Map items = ProfileItemTranslator.translator(ProfileData.getItems());
		Iterator it = items.keySet().iterator();
		while (it.hasNext()) {
			ProfileItemBean bean = (ProfileItemBean) items.get(it.next());
			vector.add(bean);
		}
	}

	public int getRowCount() {
		return vector.size();
	}

	public int getColumnCount() {
		return columnNames.length;
	}

	public String getColumnName(int column) {
		return columnNames[column];
	}

	public boolean isCellEditable(int nRow, int nCol) {
		return false;
	}

	public Object getValueAt(int nRow, int nCol) {
		switch (nCol) {
		case 0:
			return vector.elementAt(nRow).getFunction();
		case 1:
			return vector.elementAt(nRow).getCalls();
		case 2:
			return vector.elementAt(nRow).getPercent();
		case 3:
			return vector.elementAt(nRow).getOwnerTime();
		case 4:
			return vector.elementAt(nRow).getTime();
		case 5:
			return vector.elementAt(nRow).getAvg();
		case 6:
			return vector.elementAt(nRow).getMin();
		case 7:
			return vector.elementAt(nRow).getMax();
		case 8:
			return vector.elementAt(nRow).getFile();
		default:
			break;
		}
		return null;
	}

	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
		switch (columnIndex) {
		case 0:
			vector.elementAt(rowIndex).setFunction((String) aValue);
			break;
		case 1:
			vector.elementAt(rowIndex).setCalls((Integer)aValue);
			break;
		case 2:
			vector.elementAt(rowIndex).setPercent((Double) aValue);
			break;
		case 3:
			vector.elementAt(rowIndex).setOwnerTime((Long) aValue);
			break;
		case 4:
			vector.elementAt(rowIndex).setTime((Long) aValue);
			break;
		case 5:
			vector.elementAt(rowIndex).setAvg((Long) aValue);
			break;
		case 6:
			vector.elementAt(rowIndex).setMin((Long) aValue);
			break;
		case 7:
			vector.elementAt(rowIndex).setMax((Long) aValue);
			break;
		case 8:
			vector.elementAt(rowIndex).setFile((String) aValue);
			break;
		default:
			break;

		}
	}

	/**
	 * @return Returns the vector.
	 */
	public Vector<ProfileItemBean> getVector() {
		return vector;
	}

}

class ProfileItemTranslator {

	public static Map<Integer, ProfileItemBean> translator(
			Map<Integer, ProfileItem> items) {
		Map<Integer, ProfileItemBean> returnMap = new HashMap<Integer, ProfileItemBean>();
		if (items != null && !items.isEmpty()) {
			Iterator it = items.keySet().iterator();
			long total = 0;
			while (it.hasNext()) {
				Integer integer = (Integer) it.next();
				ProfileItem item = items.get(integer);
				Integer functionIndex = item.getFuncIndex();
				long currentTime = item.getTime();
				long currentTimeOwnTime = item.getTime();
				
				Integer[] relations = ProfileData.getRelations().get(integer);
				long otherTime = 0;
				if (relations != null) {
					for (Integer relation : relations) {
						otherTime += ProfileData.getItems().get(relation)
								.getTime();
					}
				}
				currentTimeOwnTime -= otherTime;

				if (returnMap.containsKey(functionIndex)) {
					ProfileItemBean bean = returnMap.get(functionIndex);
					bean.setCalls(bean.getCalls() + 1);
					bean.setMax(currentTime > bean.getMax() ? currentTime
							: bean.getMax());
					bean.setMin(currentTime < bean.getMin() ? currentTime
							: bean.getMin());
					bean.setTime(bean.getTime() + currentTime);
					bean.setOwnerTime(bean.getOwnerTime() + currentTimeOwnTime);
				} else {
					ProfileItemBean bean = new ProfileItemBean();
					bean.setCalls(1);
					bean.setFile(item.getUrl() + " (line " + item.getLine() + ")");
					bean.setFunction(item.getFuncName());
					bean.setMax(currentTime);
					bean.setMin(currentTime);
					bean.setTime(currentTime);
					bean.setOwnerTime(currentTimeOwnTime);
					returnMap.put(functionIndex, bean);
				}
				total += currentTimeOwnTime;
			}

			it = returnMap.keySet().iterator();
			while (it.hasNext()) {
				ProfileItemBean bean = returnMap.get(it.next());
				bean.setAvg(bean.getTime() / bean.getCalls());
				NumberFormat format = new DecimalFormat("#0.00");
				bean.setPercent(Double.parseDouble(format.format(bean.getOwnerTime() / 0.01 / total)));
			}
		}

		return returnMap;
	}

}

class ProfileItemBean {
	private String function;

	private int calls;

	private double percent;

	private long time;

	private long avg;

	private long min;

	private long max;

	private String file;
	
	private long ownerTime;

	/**
	 * @return the ownerTime
	 */
	public long getOwnerTime() {
		return ownerTime;
	}

	/**
	 * @param ownerTime the ownerTime to set
	 */
	public void setOwnerTime(long ownerTime) {
		this.ownerTime = ownerTime;
	}

	/**
	 * @return Returns the avg.
	 */
	public long getAvg() {
		return avg;
	}

	/**
	 * @param avg
	 *            The avg to set.
	 */
	public void setAvg(long avg) {
		this.avg = avg;
	}

	/**
	 * @return Returns the calls.
	 */
	public int getCalls() {
		return calls;
	}

	/**
	 * @param calls
	 *            The calls to set.
	 */
	public void setCalls(int calls) {
		this.calls = calls;
	}

	/**
	 * @return Returns the file.
	 */
	public String getFile() {
		return file;
	}

	/**
	 * @param file
	 *            The file to set.
	 */
	public void setFile(String file) {
		this.file = file;
	}

	/**
	 * @return Returns the function.
	 */
	public String getFunction() {
		return function;
	}

	/**
	 * @param function
	 *            The function to set.
	 */
	public void setFunction(String function) {
		this.function = function;
	}

	/**
	 * @return Returns the max.
	 */
	public long getMax() {
		return max;
	}

	/**
	 * @param max
	 *            The max to set.
	 */
	public void setMax(long max) {
		this.max = max;
	}

	/**
	 * @return Returns the min.
	 */
	public long getMin() {
		return min;
	}

	/**
	 * @param min
	 *            The min to set.
	 */
	public void setMin(long min) {
		this.min = min;
	}

	/**
	 * @return Returns the percent.
	 */
	public double getPercent() {
		return percent;
	}

	/**
	 * @param percent
	 *            The percent to set.
	 */
	public void setPercent(double percent) {
		this.percent = percent;
	}

	/**
	 * @return Returns the time.
	 */
	public long getTime() {
		return time;
	}

	/**
	 * @param time
	 *            The time to set.
	 */
	public void setTime(long time) {
		this.time = time;
	}
}
